package com.superbytecode.stencil.wrapper;

import cn.hutool.core.collection.CollectionUtil;
import com.superbytecode.stencil.entities.DatasourceContext;
import com.superbytecode.stencil.strategy.SQLStrategyFactory;
import com.superbytecode.stencil.entities.table.JavaColumn;
import com.superbytecode.stencil.entities.table.SQLColumn;
import com.superbytecode.stencil.strategy.SQLScriptStrategy;
import com.superbytecode.stencil.entities.table.SQLTable;
import com.superbytecode.stencil.entities.ConnectionObj;
import com.superbytecode.stencil.enums.DatabaseTypeEnum;
import com.superbytecode.stencil.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;

import javax.validation.constraints.NotNull;
import java.rmi.NotBoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * All rights Reserved, Designed By www.super-master.com
 *
 * @ProjectName: code-stencil
 * @Package: com.superbytecode.stencil.structure
 * @ClassName: SQLTableSelector
 * @Description: []
 * <p> </p>
 * @Author: [Lance Ting]
 * @Date: 2024/10/12 14:41
 * @Version: V1.0
 * @Copyright: 2024 www.super-master.cn Inc. All rights reserved.
 * TODO: 注意,本文件Lance Ting所作,如果转载或使用请标明具体出处!
 **/
@Slf4j
public class SQLTableSelector {
    /**
     * 数据源上下文
     */
    final private DatasourceContext context;
    /**
     * SQL数据策略接口
     */
    final private SQLScriptStrategy sqlScriptStrategy;

    public static SQLTableSelector builder(@NotNull(message = "datasource context is null") DatasourceContext context) {
        return new SQLTableSelector(context);
    }

    /*** 获取数据库表定义列表(包含表中的字段属性) ***/
    public List<SQLTable> obtainTableColumns() {
        // 加载数据库指定表结构
        List<Map<String, Object>> tableStructs = this.loadTableStructure();
        final List<SQLTable> sqlTableDefinitions = new ArrayList<>(tableStructs.size());
        tableStructs.forEach(struct -> {
            sqlTableDefinitions.add(this.warpSQLTableObj(struct));
        });
        return sqlTableDefinitions;
    }

    // =================================================================================================================
    // table 表结构

    /**
     * 包装数据表定义对象
     *
     * @param tableStructMap 表结构信息
     * @return 表对象
     */
    private SQLTable warpSQLTableObj(Map<String, Object> tableStructMap) {
        SQLTable sqlTable = sqlScriptStrategy.obtainSQLTableDefinition(tableStructMap);
        String tableName = sqlTable.getTableName();
        // 添加表中column详情
        List<JavaColumn> sqlColumns = this.warpJavaColumns(tableName);
        sqlTable.setColumns(sqlColumns);
        return sqlTable;
    }

    /**
     * 加载数据库指定表结构
     * <p>
     * 指定数据表为空，则加载数据库全部表表结构
     * </p>
     *
     * @return 表结构信息
     */
    private List<Map<String, Object>> loadTableStructure() {
        // 数据数据库的表定义结构
        String category = this.context.getCategory();
        ConnectionObj connection = this.context.getConnection();
        String databaseName = connection.getDatabaseName();
        if (StringUtil.equalsIgnoreCase(category, DatabaseTypeEnum.ORACLE11.getCategoryCode())) {
            // 如果是oracle数据库则传oracle数据库用户大写
            databaseName = StringUtil.uppercaseFirstLetter(databaseName);
        }
        // 根据不同的数据库执行查询逻辑
        String[] schTableNames = context.getSchTableNames();
        String showTablesSQL = sqlScriptStrategy.obtainSQLShowTableScript(databaseName, schTableNames);
        List<Map<String, Object>> tableStructs = this.bindScriptExecutor().runSqlScript(showTablesSQL);
        if (CollectionUtil.isEmpty(tableStructs)) {
            throw new IllegalArgumentException(String.format("not found table[%s] in %s.", databaseName, Arrays.toString(schTableNames)));
        }
        log.info("");
        return tableStructs;
    }

    // column列结构
    private List<JavaColumn> warpJavaColumns(String tableName) {
        List<JavaColumn> javaColumns = new ArrayList<>();
        this.warpSQLColumnObj(tableName).forEach(sqlColumn -> {
            javaColumns.add(JavaColumn.newInstance(sqlColumn));
        });
        return javaColumns;
    }

    /**
     * 获取指定数据表的列信息
     *
     * @param tableName 表名
     * @return 数据列
     */
    private List<SQLColumn> warpSQLColumnObj(String tableName) {
        // 获取数据表结构信息
        List<Map<String, Object>> columnStructs = this.loadColumnStructure(tableName);
        // 构建columnDefinition
        List<SQLColumn> sqlColumnDefinitions = new ArrayList<>();
        columnStructs.forEach(columnStructMap -> {
            columnStructMap.put("LTS", context.getCategoryLTS());
            // 包装数据表中列定义对象
            sqlColumnDefinitions.add(sqlScriptStrategy.obtainSQLColumnDefinition(columnStructMap));
        });
        return sqlColumnDefinitions;
    }

    /**
     * 加载数据库表的列结构
     * <p>
     * </p>
     *
     * @param tableName 表名
     * @return 表的列结构信息
     */
    private List<Map<String, Object>> loadColumnStructure(String tableName) {
        // 获取数据表结构信息
        String columnScript = sqlScriptStrategy.obtainSQLShowColumnScript(tableName);
        List<Map<String, Object>> columnStructs = this.bindScriptExecutor().runSqlScript(columnScript);
        log.info("");
        return columnStructs;
    }

    private SQLScriptExecutor bindScriptExecutor() {
        return SQLScriptExecutor.builder(this.context.getConnection());
    }

    // =================================================================================================================


    private SQLTableSelector(DatasourceContext context) {
        this.context = context;
        this.sqlScriptStrategy = SQLStrategyFactory.buildScript(context.getCategory());
    }

}